﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Net;
using Microsoft.CSharp;
using System.CodeDom.Compiler;

namespace CarseScript
{
    internal class ScriptInfo
    {
        // ID
        string  name;
        string  filePath;

        // INFO
        string  assembledCode;
        
        bool    hasErrors;
        string  errors;

        CompilerResults compiledCode;


        #region PROPERTIES


        /// <summary>
        /// Gets th assembled code string, including namespace and class statements
        /// </summary>
        internal string AssembledCode
        {
            get { return assembledCode; }
        }


        /// <summary>
        /// Gets the CompilerResults
        /// </summary>
        internal CompilerResults CompiledCode
        {
            get { return compiledCode; }
        }


        /// <summary>
        /// Returns true if there are errors in the compiled code.
        /// </summary>
        internal bool HasErrors
        {
            get { return hasErrors;}
        }


        /// <summary>
        /// Gets the error text from the CSharpCodeProvider results
        /// </summary>
        internal string Errors
        {
            get { return errors; }
        }


        /// <summary>
        /// Gets the name of the script file
        /// </summary>
        public string Name
        {
            get { return name; }
        }


        /// <summary>
        /// Gets the path to the script file
        /// </summary>
        public string FilePath
        {
            get { return filePath; }
        }
        

        #endregion

        
        internal ScriptInfo(string name, string filePath)
        {
            this.name       = name;
            this.filePath   = filePath;
            this.errors     = "";
        }
        

        internal void Process()
        {
            string rawCode = File.ReadAllText(filePath);
            
            // CHECK FOR NAME ERROR
            // script file name must follow standard c# naming rules
            if (!System.CodeDom.Compiler.CodeGenerator.IsValidLanguageIndependentIdentifier(Name))
            {
                throw new Exception("Script " + Name + " is invalid.  The name of the script must follow " +
                    "standard c# class naming rules");
            }
            
            assembledCode = rawCode;
        }
        

        /// <summary>
        /// Compiles the strings into code.
        /// </summary>
        internal void CompileCode(CompilerParameters compilerParameters, CSharpCodeProvider provider)
        {
            compiledCode = provider.CompileAssemblyFromSource(compilerParameters, assembledCode);


            // CHECK FOR ERRORS
            if (compiledCode.Errors.Count == 0)
            {
                hasErrors = false;
                return;
            }
            
            hasErrors = true;

            // we have a failure!
            StringBuilder errorBuilder = new StringBuilder();
            
            for (int i = 0; i < compiledCode.Errors.Count; i++)
            {
                int line = compiledCode.Errors[i].Line;                
                errorBuilder.AppendLine("Error in script " + Name);
                errorBuilder.AppendLine(compiledCode.Errors[i].ErrorText);
                errorBuilder.AppendLine("Line:" + line.ToString());
                errorBuilder.AppendLine("Column: " + compiledCode.Errors[i].Column.ToString());
            }

            errors = errorBuilder.ToString();
        }

    }
}
